bitkeeper revision 1.1159.72.3 (413cb565kAu26gtMpvumani1Zx6Vjw)
authorcl349@labyrinth.cl.cam.ac.uk <cl349@labyrinth.cl.cam.ac.uk>
Mon, 6 Sep 2004 19:07:17 +0000 (19:07 +0000)
committercl349@labyrinth.cl.cam.ac.uk <cl349@labyrinth.cl.cam.ac.uk>
Mon, 6 Sep 2004 19:07:17 +0000 (19:07 +0000)
Add new files in NetBSD for Xen2.0.

.rootkeys
netbsd-2.0-xen-sparse/sys/arch/xen/include/ctrl_if.h [new file with mode: 0644]
netbsd-2.0-xen-sparse/sys/arch/xen/include/evtchn.h [new file with mode: 0644]
netbsd-2.0-xen-sparse/sys/arch/xen/xen/ctrl_if.c [new file with mode: 0644]
netbsd-2.0-xen-sparse/sys/arch/xen/xen/evtchn.c [new file with mode: 0644]

index 60f058749089c29de3cadc4985a649316cb1553a..95f12c9ec592206f887feac36f9d2026fd036ecd 100644 (file)
--- a/.rootkeys
+++ b/.rootkeys
 413cb3b4aKd9SUY-OzUiTF0Gb9ve9w netbsd-2.0-xen-sparse/sys/arch/xen/i386/sys_machdep.c
 413cb3b4jUtWl-sP493PvB27o-Iltw netbsd-2.0-xen-sparse/sys/arch/xen/i386/vector.S
 413cb3b4ElwwoJEmmzflV0HgK5Qxcg netbsd-2.0-xen-sparse/sys/arch/xen/i386/xen_machdep.c
+413cb564XpMxewOF9BCK37BNcDewHQ netbsd-2.0-xen-sparse/sys/arch/xen/include/ctrl_if.h
+413cb564rB0n4HPqzYQxBvfR9r-KeQ netbsd-2.0-xen-sparse/sys/arch/xen/include/evtchn.h
 413cb3b4k9OVRCxuSdhKt-2baTp_Yg netbsd-2.0-xen-sparse/sys/arch/xen/include/frameasm.h
 413cb3b4bRsqiHQLTKEZk4-zOksf8A netbsd-2.0-xen-sparse/sys/arch/xen/include/hypervisor.h
 413cb3b4OqY83qI8GztIZGADpvrpSw netbsd-2.0-xen-sparse/sys/arch/xen/include/if_xennetvar.h
 413cb3b4y1Ffq8BOhbdSpn-fGmKuEg netbsd-2.0-xen-sparse/sys/arch/xen/include/xenpmap.h
 413cb3b4uXOFcT56QuLt1fcDrB-4Zg netbsd-2.0-xen-sparse/sys/arch/xen/x86/bus_space.c
 413cb3b4hIffjrKn3zhVqJmH6ueB3Q netbsd-2.0-xen-sparse/sys/arch/xen/xen/clock.c
+413cb564SakPue2EEm4MTtRb4z5JVw netbsd-2.0-xen-sparse/sys/arch/xen/xen/ctrl_if.c
+413cb564uNQuIozl7hperSVK9EeDCA netbsd-2.0-xen-sparse/sys/arch/xen/xen/evtchn.c
 413cb3b4eNdRIasCoQIuX4Nu39Dlqw netbsd-2.0-xen-sparse/sys/arch/xen/xen/hypervisor.c
 413cb3b40DLJLbX_ZUIULB0JFjBuaw netbsd-2.0-xen-sparse/sys/arch/xen/xen/if_xennet.c
 413cb3b46JnvK1UurZAubeQoFg1W-w netbsd-2.0-xen-sparse/sys/arch/xen/xen/xbd.c
diff --git a/netbsd-2.0-xen-sparse/sys/arch/xen/include/ctrl_if.h b/netbsd-2.0-xen-sparse/sys/arch/xen/include/ctrl_if.h
new file mode 100644 (file)
index 0000000..6d6bfe1
--- /dev/null
@@ -0,0 +1,138 @@
+/******************************************************************************
+ * ctrl_if.h
+ * 
+ * Management functions for special interface to the domain controller.
+ * 
+ * Copyright (c) 2004, K A Fraser
+ */
+
+#ifndef __ASM_XEN__CTRL_IF_H__
+#define __ASM_XEN__CTRL_IF_H__
+
+typedef control_msg_t ctrl_msg_t;
+
+/*
+ * Callback function type. Called for asynchronous processing of received
+ * request messages, and responses to previously-transmitted request messages.
+ * The parameters are (@msg, @id).
+ *  @msg: Original request/response message (not a copy). The message can be
+ *        modified in-place by the handler (e.g., a response callback can
+ *        turn a request message into a response message in place). The message
+ *        is no longer accessible after the callback handler returns -- if the
+ *        message is required to persist for longer then it must be copied.
+ *  @id:  (Response callbacks only) The 'id' that was specified when the
+ *        original request message was queued for transmission.
+ */
+typedef void (*ctrl_msg_handler_t)(ctrl_msg_t *, unsigned long);
+
+/*
+ * Send @msg to the domain controller. Execute @hnd when a response is
+ * received, passing the response message and the specified @id. This
+ * operation will not block: it will return -EAGAIN if there is no space.
+ * Notes:
+ *  1. The @msg is copied if it is transmitted and so can be freed after this
+ *     function returns.
+ *  2. If @hnd is NULL then no callback is executed.
+ */
+int
+ctrl_if_send_message_noblock(
+    ctrl_msg_t *msg, 
+    ctrl_msg_handler_t hnd,
+    unsigned long id);
+
+/*
+ * Send @msg to the domain controller. Execute @hnd when a response is
+ * received, passing the response message and the specified @id. This
+ * operation will block until the message is sent, or a signal is received
+ * for the calling process (unless @wait_state is TASK_UNINTERRUPTIBLE).
+ * Notes:
+ *  1. The @msg is copied if it is transmitted and so can be freed after this
+ *     function returns.
+ *  2. If @hnd is NULL then no callback is executed.
+ */
+int
+ctrl_if_send_message_block(
+    ctrl_msg_t *msg, 
+    ctrl_msg_handler_t hnd, 
+    unsigned long id, 
+    long wait_state);
+
+/*
+ * Send @msg to the domain controller. Block until the response is received,
+ * and then copy it into the provided buffer, @rmsg.
+ */
+int
+ctrl_if_send_message_and_get_response(
+    ctrl_msg_t *msg,
+    ctrl_msg_t *rmsg,
+    long wait_state);
+
+#ifdef notyet
+/*
+ * Request a callback when there is /possibly/ space to immediately send a
+ * message to the domain controller. This function returns 0 if there is
+ * already space to trasnmit a message --- in this case the callback task /may/
+ * still be executed. If this function returns 1 then the callback /will/ be
+ * executed when space becomes available.
+ */
+int
+ctrl_if_enqueue_space_callback(
+    struct tq_struct *task);
+#endif
+
+/*
+ * Send a response (@msg) to a message from the domain controller. This will 
+ * never block.
+ * Notes:
+ *  1. The @msg is copied and so can be freed after this function returns.
+ *  2. The @msg may be the original request message, modified in-place.
+ */
+void
+ctrl_if_send_response(
+    ctrl_msg_t *msg);
+
+/*
+ * Register a receiver for typed messages from the domain controller. The 
+ * handler (@hnd) is called for every received message of specified @type.
+ * Returns TRUE (non-zero) if the handler was successfully registered.
+ * If CALLBACK_IN_BLOCKING CONTEXT is specified in @flags then callbacks will
+ * occur in a context in which it is safe to yield (i.e., process context).
+ */
+#define CALLBACK_IN_BLOCKING_CONTEXT 1
+int ctrl_if_register_receiver(
+    uint8_t type, 
+    ctrl_msg_handler_t hnd,
+    unsigned int flags);
+
+/*
+ * Unregister a receiver for typed messages from the domain controller. The 
+ * handler (@hnd) will not be executed after this function returns.
+ */
+void
+ctrl_if_unregister_receiver(
+    uint8_t type, ctrl_msg_handler_t hnd);
+
+/* Suspend/resume notifications. */
+void ctrl_if_suspend(void);
+void ctrl_if_resume(void);
+
+/* Start-of-day setup. */
+void ctrl_if_init(void);
+
+/*
+ * Returns TRUE if there are no outstanding message requests at the domain
+ * controller. This can be used to ensure that messages have really flushed
+ * through when it is not possible to use the response-callback interface.
+ * WARNING: If other subsystems are using the control interface then this
+ * function might never return TRUE!
+ */
+int ctrl_if_transmitter_empty(void);  /* !! DANGEROUS FUNCTION !! */
+
+/*
+ * Manually discard response messages from the domain controller. 
+ * WARNING: This is usually done automatically -- this function should only
+ * be called when normal interrupt mechanisms are disabled!
+ */
+void ctrl_if_discard_responses(void); /* !! DANGEROUS FUNCTION !! */
+
+#endif /* __ASM_XEN__CONTROL_IF_H__ */
diff --git a/netbsd-2.0-xen-sparse/sys/arch/xen/include/evtchn.h b/netbsd-2.0-xen-sparse/sys/arch/xen/include/evtchn.h
new file mode 100644 (file)
index 0000000..5dd98ef
--- /dev/null
@@ -0,0 +1,53 @@
+/*     $NetBSD$        */
+
+/*
+ *
+ * Copyright (c) 2004 Christian Limpach.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *      This product includes software developed by Christian Limpach.
+ * 4. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _XEN_EVENTS_H_
+#define _XEN_EVENTS_H_
+
+#define        NR_IRQS         32
+
+extern int evtchn_to_irq[];
+
+/* typedef unsigned int (*ev_handler_t)(int, struct pt_regs *); */
+typedef int (*ev_handler_t)(void *);
+
+void events_default_setup(void);
+void init_events(void);
+unsigned int do_event(int, struct trapframe *);
+int event_set_handler(int, ev_handler_t, void *, int);
+
+int bind_virq_to_irq(int);
+void unbind_virq_from_irq(int);
+int bind_evtchn_to_irq(int);
+
+#endif /*  _XEN_EVENTS_H_ */
diff --git a/netbsd-2.0-xen-sparse/sys/arch/xen/xen/ctrl_if.c b/netbsd-2.0-xen-sparse/sys/arch/xen/xen/ctrl_if.c
new file mode 100644 (file)
index 0000000..39b4feb
--- /dev/null
@@ -0,0 +1,573 @@
+/******************************************************************************
+ * ctrl_if.c
+ * 
+ * Management functions for special interface to the domain controller.
+ * 
+ * Copyright (c) 2004, K A Fraser
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+#include <sys/malloc.h>
+#include <sys/kthread.h>
+
+#include <machine/xen.h>
+#include <machine/hypervisor.h>
+#include <machine/ctrl_if.h>
+#include <machine/evtchn.h>
+
+#if 0
+#define DPRINTK(_f, _a...) printf("(file=%s, line=%d) " _f, \
+                           __FILE__ , __LINE__ , ## _a )
+#else
+#define DPRINTK(_f, _a...) ((void)0)
+#endif
+
+/*
+ * Only used by initial domain which must create its own control-interface
+ * event channel. This value is picked up by the user-space domain controller
+ * via an ioctl.
+ */
+int initdom_ctrlif_domcontroller_port = -1;
+
+static int ctrl_if_evtchn;
+static int ctrl_if_irq;
+static struct simplelock ctrl_if_lock;
+
+static CONTROL_RING_IDX ctrl_if_tx_resp_cons;
+static CONTROL_RING_IDX ctrl_if_rx_req_cons;
+
+/* Incoming message requests. */
+    /* Primary message type -> message handler. */
+static ctrl_msg_handler_t ctrl_if_rxmsg_handler[256];
+    /* Primary message type -> callback in process context? */
+static unsigned long ctrl_if_rxmsg_blocking_context[256/sizeof(unsigned long)];
+#if 0
+    /* Is it late enough during bootstrap to use schedule_task()? */
+static int safe_to_schedule_task;
+#endif
+    /* Queue up messages to be handled in process context. */
+static ctrl_msg_t ctrl_if_rxmsg_deferred[CONTROL_RING_SIZE];
+static CONTROL_RING_IDX ctrl_if_rxmsg_deferred_prod;
+static CONTROL_RING_IDX ctrl_if_rxmsg_deferred_cons;
+
+/* Incoming message responses: message identifier -> message handler/id. */
+static struct {
+    ctrl_msg_handler_t fn;
+    unsigned long      id;
+} ctrl_if_txmsg_id_mapping[CONTROL_RING_SIZE];
+
+/* For received messages that must be deferred to process context. */
+static void __ctrl_if_rxmsg_deferred(void *unused);
+
+#ifdef notyet
+/* Deferred callbacks for people waiting for space in the transmit ring. */
+static int DECLARE_TASK_QUEUE(ctrl_if_tx_tq);
+#endif
+
+static void *ctrl_if_softintr = NULL;
+
+static int ctrl_if_tx_wait;
+static void __ctrl_if_tx_tasklet(unsigned long data);
+
+static void __ctrl_if_rx_tasklet(unsigned long data);
+
+static void ctrl_if_kthread(void *);
+
+#define get_ctrl_if() ((control_if_t *)((char *)HYPERVISOR_shared_info + 2048))
+#define TX_FULL(_c)   \
+    (((_c)->tx_req_prod - ctrl_if_tx_resp_cons) == CONTROL_RING_SIZE)
+
+static void ctrl_if_notify_controller(void)
+{
+    hypervisor_notify_via_evtchn(ctrl_if_evtchn);
+}
+
+static void ctrl_if_rxmsg_default_handler(ctrl_msg_t *msg, unsigned long id)
+{
+    msg->length = 0;
+    ctrl_if_send_response(msg);
+}
+
+static void __ctrl_if_tx_tasklet(unsigned long data)
+{
+    control_if_t *ctrl_if = get_ctrl_if();
+    ctrl_msg_t   *msg;
+    int           was_full = TX_FULL(ctrl_if);
+    CONTROL_RING_IDX rp;
+
+    rp = ctrl_if->tx_resp_prod;
+    __insn_barrier(); /* Ensure we see all requests up to 'rp'. */
+
+    while ( ctrl_if_tx_resp_cons != rp )
+    {
+        msg = &ctrl_if->tx_ring[MASK_CONTROL_IDX(ctrl_if_tx_resp_cons)];
+
+        DPRINTK("Rx-Rsp %u/%u :: %d/%d\n", 
+                ctrl_if_tx_resp_cons,
+                ctrl_if->tx_resp_prod,
+                msg->type, msg->subtype);
+
+        /* Execute the callback handler, if one was specified. */
+        if ( msg->id != 0xFF )
+        {
+            (*ctrl_if_txmsg_id_mapping[msg->id].fn)(
+                msg, ctrl_if_txmsg_id_mapping[msg->id].id);
+            __insn_barrier(); /* Execute, /then/ free. */
+            ctrl_if_txmsg_id_mapping[msg->id].fn = NULL;
+        }
+
+        /*
+         * Step over the message in the ring /after/ finishing reading it. As 
+         * soon as the index is updated then the message may get blown away.
+         */
+        __insn_barrier();
+        ctrl_if_tx_resp_cons++;
+    }
+
+    if ( was_full && !TX_FULL(ctrl_if) )
+    {
+        wakeup(&ctrl_if_tx_wait);
+#ifdef notyet
+        run_task_queue(&ctrl_if_tx_tq);
+#endif
+    }
+}
+
+static void __ctrl_if_rxmsg_deferred(void *unused)
+{
+       ctrl_msg_t *msg;
+       CONTROL_RING_IDX dp;
+
+       dp = ctrl_if_rxmsg_deferred_prod;
+       __insn_barrier(); /* Ensure we see all deferred requests up to 'dp'. */
+
+       while ( ctrl_if_rxmsg_deferred_cons != dp )
+       {
+               msg = &ctrl_if_rxmsg_deferred[MASK_CONTROL_IDX(
+                                                     ctrl_if_rxmsg_deferred_cons++)];
+               (*ctrl_if_rxmsg_handler[msg->type])(msg, 0);
+       }
+}
+
+static void __ctrl_if_rx_tasklet(unsigned long data)
+{
+    control_if_t *ctrl_if = get_ctrl_if();
+    ctrl_msg_t    msg, *pmsg;
+    CONTROL_RING_IDX rp, dp;
+
+    dp = ctrl_if_rxmsg_deferred_prod;
+    rp = ctrl_if->rx_req_prod;
+    __insn_barrier(); /* Ensure we see all requests up to 'rp'. */
+
+    while ( ctrl_if_rx_req_cons != rp )
+    {
+        pmsg = &ctrl_if->rx_ring[MASK_CONTROL_IDX(ctrl_if_rx_req_cons++)];
+        memcpy(&msg, pmsg, offsetof(ctrl_msg_t, msg));
+
+        DPRINTK("Rx-Req %u/%u :: %d/%d\n", 
+                ctrl_if_rx_req_cons-1,
+                ctrl_if->rx_req_prod,
+                msg.type, msg.subtype);
+
+        if ( msg.length != 0 )
+            memcpy(msg.msg, pmsg->msg, msg.length);
+
+        if ( x86_atomic_test_bit(
+                      (unsigned long *)&ctrl_if_rxmsg_blocking_context,
+                     msg.type) )
+            memcpy(&ctrl_if_rxmsg_deferred[MASK_CONTROL_IDX(dp++)],
+                   &msg, offsetof(ctrl_msg_t, msg) + msg.length);
+        else
+            (*ctrl_if_rxmsg_handler[msg.type])(&msg, 0);
+    }
+
+    if ( dp != ctrl_if_rxmsg_deferred_prod )
+    {
+        __insn_barrier();
+        ctrl_if_rxmsg_deferred_prod = dp;
+#if 0
+        wakeup(&ctrl_if_kthread);
+#else
+       if (ctrl_if_softintr)
+               softintr_schedule(ctrl_if_softintr);
+#endif
+    }
+}
+
+static int ctrl_if_interrupt(void *arg)
+{
+    control_if_t *ctrl_if = get_ctrl_if();
+
+    if ( ctrl_if_tx_resp_cons != ctrl_if->tx_resp_prod ||
+       ctrl_if_rx_req_cons != ctrl_if->rx_req_prod ) {
+#if 0
+           wakeup(&ctrl_if_kthread);
+#else
+           if (ctrl_if_softintr)
+                   softintr_schedule(ctrl_if_softintr);
+#endif
+    }
+
+    return 0;
+}
+
+int
+ctrl_if_send_message_noblock(
+    ctrl_msg_t *msg, 
+    ctrl_msg_handler_t hnd,
+    unsigned long id)
+{
+    control_if_t *ctrl_if = get_ctrl_if();
+    unsigned long flags;
+    int           i;
+
+    save_and_cli(flags);
+    simple_lock(&ctrl_if_lock);
+
+    if ( TX_FULL(ctrl_if) )
+    {
+        simple_unlock(&ctrl_if_lock);
+       restore_flags(flags);
+        return -EAGAIN;
+    }
+
+    msg->id = 0xFF;
+    if ( hnd != NULL )
+    {
+        for ( i = 0; ctrl_if_txmsg_id_mapping[i].fn != NULL; i++ )
+            continue;
+        ctrl_if_txmsg_id_mapping[i].fn = hnd;
+        ctrl_if_txmsg_id_mapping[i].id = id;
+        msg->id = i;
+    }
+
+    DPRINTK("Tx-Req %u/%u :: %d/%d\n", 
+            ctrl_if->tx_req_prod, 
+            ctrl_if_tx_resp_cons,
+            msg->type, msg->subtype);
+
+    memcpy(&ctrl_if->tx_ring[MASK_CONTROL_IDX(ctrl_if->tx_req_prod)], 
+           msg, sizeof(*msg));
+    __insn_barrier(); /* Write the message before letting the controller peek at it. */
+    ctrl_if->tx_req_prod++;
+
+    simple_unlock(&ctrl_if_lock);
+    restore_flags(flags);
+
+    ctrl_if_notify_controller();
+
+    return 0;
+}
+
+int
+ctrl_if_send_message_block(
+    ctrl_msg_t *msg, 
+    ctrl_msg_handler_t hnd, 
+    unsigned long id,
+    long wait_state)
+{
+       int rc;
+
+       while ((rc = ctrl_if_send_message_noblock(msg, hnd, id)) == EAGAIN) {
+               /* XXXcl possible race -> add a lock and ltsleep */
+               rc = tsleep((caddr_t) &ctrl_if_tx_wait, PUSER | PCATCH,
+                   "ctrl_if", 0);
+               if (rc)
+                       break;
+       }
+
+       return rc;
+}
+
+/* Allow a reponse-callback handler to find context of a blocked requester.  */
+struct rsp_wait {
+    ctrl_msg_t         *msg;  /* Buffer for the response message.            */
+    struct task_struct *task; /* The task that is blocked on the response.   */
+    int                 done; /* Indicate to 'task' that response is rcv'ed. */
+};
+
+static void __ctrl_if_get_response(ctrl_msg_t *msg, unsigned long id)
+{
+    struct rsp_wait    *wait = (struct rsp_wait *)id;
+
+    memcpy(wait->msg, msg, sizeof(*msg));
+    __insn_barrier();
+    wait->done = 1;
+
+    wakeup(wait);
+}
+
+int
+ctrl_if_send_message_and_get_response(
+    ctrl_msg_t *msg, 
+    ctrl_msg_t *rmsg,
+    long wait_state)
+{
+    struct rsp_wait wait;
+    int rc;
+
+    wait.msg  = rmsg;
+    wait.done = 0;
+
+    if ( (rc = ctrl_if_send_message_block(msg, __ctrl_if_get_response,
+                                          (unsigned long)&wait,
+                                          wait_state)) != 0 )
+        return rc;
+
+    for ( ; ; )
+    {
+           if ( wait.done )
+                   break;
+           tsleep((caddr_t)&wait, PUSER | PCATCH, "ctrl_if", 0);
+    }
+
+    return 0;
+}
+
+#ifdef notyet
+int
+ctrl_if_enqueue_space_callback(
+    struct tq_struct *task)
+{
+    control_if_t *ctrl_if = get_ctrl_if();
+
+    /* Fast path. */
+    if ( !TX_FULL(ctrl_if) )
+        return 0;
+
+    (void)queue_task(task, &ctrl_if_tx_tq);
+
+    /*
+     * We may race execution of the task queue, so return re-checked status. If
+     * the task is not executed despite the ring being non-full then we will
+     * certainly return 'not full'.
+     */
+    __insn_barrier();
+    return TX_FULL(ctrl_if);
+}
+#endif
+
+void
+ctrl_if_send_response(
+    ctrl_msg_t *msg)
+{
+    control_if_t *ctrl_if = get_ctrl_if();
+    unsigned long flags;
+    ctrl_msg_t   *dmsg;
+
+    /*
+     * NB. The response may the original request message, modified in-place.
+     * In this situation we may have src==dst, so no copying is required.
+     */
+    save_and_cli(flags);
+    simple_lock(&ctrl_if_lock);
+
+    DPRINTK("Tx-Rsp %u :: %d/%d\n", 
+            ctrl_if->rx_resp_prod, 
+            msg->type, msg->subtype);
+
+    dmsg = &ctrl_if->rx_ring[MASK_CONTROL_IDX(ctrl_if->rx_resp_prod)];
+    if ( dmsg != msg )
+        memcpy(dmsg, msg, sizeof(*msg));
+
+    __insn_barrier(); /* Write the message before letting the controller peek at it. */
+    ctrl_if->rx_resp_prod++;
+
+    simple_unlock(&ctrl_if_lock);
+    restore_flags(flags);
+
+    ctrl_if_notify_controller();
+}
+
+int
+ctrl_if_register_receiver(
+    uint8_t type, 
+    ctrl_msg_handler_t hnd, 
+    unsigned int flags)
+{
+    unsigned long _flags;
+    int inuse;
+
+    save_and_cli(_flags);
+    simple_lock(&ctrl_if_lock);
+
+    inuse = (ctrl_if_rxmsg_handler[type] != ctrl_if_rxmsg_default_handler);
+
+    if ( inuse )
+    {
+        printf("Receiver %p already established for control "
+               "messages of type %d.\n", ctrl_if_rxmsg_handler[type], type);
+    }
+    else
+    {
+        ctrl_if_rxmsg_handler[type] = hnd;
+        x86_atomic_clear_bit((unsigned long *)&ctrl_if_rxmsg_blocking_context, type);
+        if ( flags == CALLBACK_IN_BLOCKING_CONTEXT )
+        {
+            x86_atomic_set_bit((unsigned long *)&ctrl_if_rxmsg_blocking_context, type);
+#if 0
+            if ( !safe_to_schedule_task )
+                BUG();
+#endif
+        }
+    }
+
+    simple_unlock(&ctrl_if_lock);
+    restore_flags(_flags);
+
+    return !inuse;
+}
+
+void 
+ctrl_if_unregister_receiver(
+    uint8_t type,
+    ctrl_msg_handler_t hnd)
+{
+    unsigned long flags;
+
+    save_and_cli(flags);
+    simple_lock(&ctrl_if_lock);
+
+    if ( ctrl_if_rxmsg_handler[type] != hnd )
+        printf("Receiver %p is not registered for control "
+               "messages of type %d.\n", hnd, type);
+    else
+        ctrl_if_rxmsg_handler[type] = ctrl_if_rxmsg_default_handler;
+
+    simple_unlock(&ctrl_if_lock);
+    restore_flags(flags);
+
+    /* Ensure that @hnd will not be executed after this function returns. */
+#if 0
+    wakeup(&ctrl_if_kthread);
+#else
+    if (ctrl_if_softintr)
+           softintr_schedule(ctrl_if_softintr);
+#endif
+}
+
+static void
+ctrl_if_kthread(void *arg)
+{
+       control_if_t *ctrl_if = get_ctrl_if();
+
+       // printf("ctrl_if_kthread starting\n");
+       for (;;) {
+               if ( ctrl_if_tx_resp_cons != ctrl_if->tx_resp_prod )
+                       __ctrl_if_tx_tasklet(0);
+
+               if ( ctrl_if_rx_req_cons != ctrl_if->rx_req_prod )
+                       __ctrl_if_rx_tasklet(0);
+
+               if ( ctrl_if_rxmsg_deferred_cons !=
+                   ctrl_if_rxmsg_deferred_prod )
+                       __ctrl_if_rxmsg_deferred(NULL);
+
+               if (arg) {
+                       // printf("ctrl_if_kthread one-shot done\n");
+                       return;
+               }
+
+               tsleep((caddr_t)&ctrl_if_kthread, PUSER | PCATCH,
+                   "ctrl_if", 0);
+       }
+}
+
+static void
+ctrl_if_create_kthread(void *arg)
+{
+
+       printf("ctrl_if_kthread creating\n");
+       if (kthread_create1(ctrl_if_kthread, arg, NULL, "ctrl_if"))
+               printf("ctrl_if_kthread create failed\n");
+       softintr_schedule(ctrl_if_softintr);
+}
+
+#ifdef notyet
+void ctrl_if_suspend(void)
+{
+    free_irq(ctrl_if_irq, NULL);
+    unbind_evtchn_from_irq(ctrl_if_evtchn);
+}
+#endif
+
+void ctrl_if_resume(void)
+{
+    control_if_t *ctrl_if = get_ctrl_if();
+
+    if ( xen_start_info.flags & SIF_INITDOMAIN )
+    {
+        /*
+         * The initial domain must create its own domain-controller link.
+         * The controller is probably not running at this point, but will
+         * pick up its end of the event channel from 
+         */
+        evtchn_op_t op;
+        op.cmd = EVTCHNOP_bind_interdomain;
+        op.u.bind_interdomain.dom1 = DOMID_SELF;
+        op.u.bind_interdomain.dom2 = DOMID_SELF;
+        if ( HYPERVISOR_event_channel_op(&op) != 0 )
+               panic("EVTCHNOP_bind_interdomain");
+        xen_start_info.domain_controller_evtchn = op.u.bind_interdomain.port1;
+        initdom_ctrlif_domcontroller_port   = op.u.bind_interdomain.port2;
+    }
+
+    /* Sync up with shared indexes. */
+    ctrl_if_tx_resp_cons = ctrl_if->tx_resp_prod;
+    ctrl_if_rx_req_cons  = ctrl_if->rx_resp_prod;
+
+    ctrl_if_evtchn = xen_start_info.domain_controller_evtchn;
+    ctrl_if_irq    = bind_evtchn_to_irq(ctrl_if_evtchn);
+
+    event_set_handler(ctrl_if_irq, &ctrl_if_interrupt, NULL, IPL_HIGH);
+    hypervisor_enable_irq(ctrl_if_irq);
+}
+
+void ctrl_if_init(void)
+{
+        int i;
+
+    for ( i = 0; i < 256; i++ )
+        ctrl_if_rxmsg_handler[i] = ctrl_if_rxmsg_default_handler;
+
+    simple_lock_init(&ctrl_if_lock);
+
+    if (0) kthread_create(ctrl_if_create_kthread, NULL);
+    ctrl_if_softintr =
+           softintr_establish(IPL_SOFTNET, ctrl_if_kthread, (void *)1);
+
+    ctrl_if_resume();
+}
+
+
+#if 0
+/* This is called after it is safe to call schedule_task(). */
+static int __init ctrl_if_late_setup(void)
+{
+    safe_to_schedule_task = 1;
+    return 0;
+}
+__initcall(ctrl_if_late_setup);
+#endif
+
+
+/*
+ * !! The following are DANGEROUS FUNCTIONS !!
+ * Use with care [for example, see xencons_force_flush()].
+ */
+
+int ctrl_if_transmitter_empty(void)
+{
+    return (get_ctrl_if()->tx_req_prod == ctrl_if_tx_resp_cons);
+}
+
+void ctrl_if_discard_responses(void)
+{
+    ctrl_if_tx_resp_cons = get_ctrl_if()->tx_resp_prod;
+}
+
diff --git a/netbsd-2.0-xen-sparse/sys/arch/xen/xen/evtchn.c b/netbsd-2.0-xen-sparse/sys/arch/xen/xen/evtchn.c
new file mode 100644 (file)
index 0000000..ca3f7c9
--- /dev/null
@@ -0,0 +1,347 @@
+/*     $NetBSD$        */
+
+/*
+ *
+ * Copyright (c) 2004 Christian Limpach.
+ * Copyright (c) 2004, K A Fraser.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *      This product includes software developed by Christian Limpach.
+ * 4. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+#include <sys/malloc.h>
+#include <sys/reboot.h>
+
+#include <uvm/uvm.h>
+
+#include <machine/intrdefs.h>
+
+#include <machine/xen.h>
+#include <machine/hypervisor.h>
+#include <machine/evtchn.h>
+#include <machine/ctrl_if.h>
+#include <machine/xenfunc.h>
+
+struct pic xenev_pic = {
+       .pic_dev = {
+               .dv_xname = "xen_fakepic",
+       },
+       .pic_type = PIC_XEN,
+       .pic_lock = __SIMPLELOCK_UNLOCKED,
+};
+
+/*
+ * This lock protects updates to the following mapping and reference-count
+ * arrays. The lock does not need to be acquired to read the mapping tables.
+ */
+static struct simplelock irq_mapping_update_lock = SIMPLELOCK_INITIALIZER;
+
+/* IRQ <-> event-channel mappings. */
+int evtchn_to_irq[NR_EVENT_CHANNELS];
+int irq_to_evtchn[NR_IRQS];
+
+/* IRQ <-> VIRQ mapping. */
+static int virq_to_irq[NR_VIRQS];
+
+/* Reference counts for bindings to IRQs. */
+static int irq_bindcount[NR_IRQS];
+
+#if 0
+static int xen_die_handler(void *);
+#endif
+static int xen_debug_handler(void *);
+static int xen_misdirect_handler(void *);
+
+void
+events_default_setup()
+{
+       int i;
+
+       /* No VIRQ -> IRQ mappings. */
+       for (i = 0; i < NR_VIRQS; i++)
+               virq_to_irq[i] = -1;
+
+       /* No event-channel -> IRQ mappings. */
+       for (i = 0; i < NR_EVENT_CHANNELS; i++) {
+               evtchn_to_irq[i] = -1;
+               hypervisor_mask_event(i); /* No event channels are 'live' right now. */
+       }
+
+       /* No IRQ -> event-channel mappings. */
+       for (i = 0; i < NR_IRQS; i++)
+               irq_to_evtchn[i] = -1;
+}
+
+void
+init_events()
+{
+       int irq;
+
+       irq = bind_virq_to_irq(VIRQ_DEBUG);
+       event_set_handler(irq, &xen_debug_handler, NULL, IPL_DEBUG);
+       hypervisor_enable_irq(irq);
+
+       irq = bind_virq_to_irq(VIRQ_MISDIRECT);
+       event_set_handler(irq, &xen_misdirect_handler, NULL, IPL_DIE);
+       hypervisor_enable_irq(irq);
+
+       /* This needs to be done early, but after the IRQ subsystem is
+        * alive. */
+       ctrl_if_init();
+
+       enable_intr();          /* at long last... */
+}
+
+unsigned int
+do_event(int irq, struct trapframe *regs)
+{
+       struct cpu_info *ci;
+
+       if (irq >= NR_IRQS) {
+#ifdef DIAGNOSTIC
+               printf("event irq number %d > NR_IRQS\n", irq);
+#endif
+               return ENOENT;
+       }
+
+       if (0 && irq == 4) {
+               ci = &cpu_info_primary;
+               printf("do_event %d/%d called, ilevel %d\n", irq,
+                      irq_to_evtchn[irq], ci->ci_ilevel);
+       }
+
+       ci = &cpu_info_primary;
+
+       hypervisor_acknowledge_irq(irq);
+       if (ci->ci_isources[irq] == NULL) {
+               return 0;
+       }
+       __asm__ __volatile__ (
+               "   movl $1f,%%esi      ;"
+               "   jmp  *%%eax         ;"
+               "1:                     "
+               : : "a" (ci->ci_isources[irq]->is_recurse),
+               "b" (ci->ci_ilevel)
+               : "esi", "ecx", "edx", "memory");
+
+       if (0 && irq == 4)
+               printf("do_event %d done, ipending %08x\n", irq,
+                   ci->ci_ipending);
+
+       return 0;
+}
+
+static int
+find_unbound_irq(void)
+{
+       int irq;
+
+       for (irq = 0; irq < NR_IRQS; irq++)
+               if (irq_bindcount[irq] == 0)
+                       break;
+
+       if (irq == NR_IRQS)
+               panic("No available IRQ to bind to: increase NR_IRQS!\n");
+
+       return irq;
+}
+
+int
+bind_virq_to_irq(int virq)
+{
+       evtchn_op_t op;
+       int evtchn, irq;
+
+       simple_lock(&irq_mapping_update_lock);
+
+       irq = virq_to_irq[virq];
+       if (irq == -1) {
+               op.cmd = EVTCHNOP_bind_virq;
+               op.u.bind_virq.virq = virq;
+               if (HYPERVISOR_event_channel_op(&op) != 0)
+                       panic("Failed to bind virtual IRQ %d\n", virq);
+               evtchn = op.u.bind_virq.port;
+
+               irq = find_unbound_irq();
+               evtchn_to_irq[evtchn] = irq;
+               irq_to_evtchn[irq] = evtchn;
+
+               virq_to_irq[virq] = irq;
+       }
+
+       irq_bindcount[irq]++;
+
+       simple_unlock(&irq_mapping_update_lock);
+    
+       return irq;
+}
+
+void
+unbind_virq_from_irq(int virq)
+{
+       evtchn_op_t op;
+       int irq = virq_to_irq[virq];
+       int evtchn = irq_to_evtchn[irq];
+
+       simple_lock(&irq_mapping_update_lock);
+
+       irq_bindcount[irq]--;
+       if (irq_bindcount[irq] == 0) {
+               op.cmd = EVTCHNOP_close;
+               op.u.close.dom = DOMID_SELF;
+               op.u.close.port = evtchn;
+               if (HYPERVISOR_event_channel_op(&op) != 0)
+                       panic("Failed to unbind virtual IRQ %d\n", virq);
+
+               evtchn_to_irq[evtchn] = -1;
+               irq_to_evtchn[irq] = -1;
+               virq_to_irq[virq] = -1;
+       }
+
+       simple_unlock(&irq_mapping_update_lock);
+}
+
+int bind_evtchn_to_irq(int evtchn)
+{
+       int irq;
+
+       simple_lock(&irq_mapping_update_lock);
+
+       irq = evtchn_to_irq[evtchn];
+       if (irq == -1) {
+               irq = find_unbound_irq();
+               evtchn_to_irq[evtchn] = irq;
+               irq_to_evtchn[irq] = evtchn;
+       }
+
+       irq_bindcount[irq]++;
+
+       simple_unlock(&irq_mapping_update_lock);
+    
+       return irq;
+}
+
+int
+event_set_handler(int irq, ev_handler_t handler, void *arg, int level)
+{
+       struct intrsource *isp;
+       struct intrhand *ih;
+       struct cpu_info *ci;
+
+       if (irq >= NR_IRQS) {
+#ifdef DIAGNOSTIC
+               printf("irq number %d > NR_IRQS\n", irq);
+#endif
+               return ENOENT;
+       }
+
+#if 0
+       printf("event_set_handler irq %d/%d handler %p level %d\n", irq,
+              irq_to_evtchn[irq], handler, level);
+#endif
+       /* XXXcl handle already bound irq */
+
+       MALLOC(isp, struct intrsource *, sizeof (struct intrsource), M_DEVBUF,
+           M_WAITOK|M_ZERO);
+       if (isp == NULL)
+               panic("can't allocate fixed interrupt source");
+       MALLOC(ih, struct intrhand *, sizeof (struct intrhand), M_DEVBUF,
+           M_WAITOK|M_ZERO);
+       if (ih == NULL)
+               panic("can't allocate fixed interrupt source");
+
+       ci = &cpu_info_primary;
+
+       isp->is_recurse = xenev_stubs[irq].ist_recurse;
+       isp->is_resume = xenev_stubs[irq].ist_resume;
+       ih->ih_level = level;
+       ih->ih_fun = handler;
+       ih->ih_arg = arg;
+       ih->ih_next = NULL;
+       isp->is_handlers = ih;
+       isp->is_pic = &xenev_pic;
+       ci->ci_isources[irq] = isp;
+       evcnt_attach_dynamic(&isp->is_evcnt, EVCNT_TYPE_INTR, NULL,
+           ci->ci_dev->dv_xname, "xenev");
+
+       intr_calculatemasks(ci);
+
+       return 0;
+}
+
+void hypervisor_enable_irq(unsigned int irq)
+{
+
+       hypervisor_unmask_event(irq_to_evtchn[irq]);
+}
+
+void hypervisor_disable_irq(unsigned int irq)
+{
+
+       hypervisor_mask_event(irq_to_evtchn[irq]);
+}
+
+void hypervisor_acknowledge_irq(unsigned int irq)
+{
+
+       hypervisor_mask_event(irq_to_evtchn[irq]);
+       hypervisor_clear_event(irq_to_evtchn[irq]);
+}
+
+#if 0
+static int
+xen_die_handler(void *arg)
+{
+       printf("hypervisor: DIE event received...\n");
+       cpu_reboot(0, NULL);
+       /* NOTREACHED */
+       return 0;
+}
+#endif
+
+static int
+xen_debug_handler(void *arg)
+{
+       printf("debug event\n");
+       return 0;
+}
+
+static int
+xen_misdirect_handler(void *arg)
+{
+#if 0
+       char *msg = "misdirect\n";
+       (void)HYPERVISOR_console_io(CONSOLEIO_write, strlen(msg), msg);
+#endif
+       return 0;
+}